package com.bookocean.infrastructure.config;

import com.bookocean.domain.utils.JwtUtils;
import com.bookocean.domain.utils.UserContextHolder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 认证拦截器
 * 拦截需要认证的请求，验证JWT令牌并设置用户上下文
 * 
 * @author BookOcean
 * @since 2024-01-01
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class AuthenticationInterceptor implements HandlerInterceptor {

    private final JwtUtils jwtUtils;
    private final JwtProperties jwtProperties;

    /**
     * 请求处理前的拦截
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 获取请求路径
        String requestPath = request.getRequestURI();
        log.debug("拦截请求: {} {}", request.getMethod(), requestPath);

        // 跳过不需要认证的接口
        if (isPublicPath(requestPath)) {
            log.debug("公开接口，跳过认证: {}", requestPath);
            return true;
        }

        // 从请求头中获取JWT令牌
        String token = getTokenFromRequest(request);
        if (!StringUtils.hasText(token)) {
            log.warn("请求缺少认证令牌: {}", requestPath);
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }

        // 验证令牌
        if (!jwtUtils.validateToken(token)) {
            log.warn("无效的认证令牌: {}", requestPath);
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }

        // 从令牌中提取用户信息并设置到上下文
        try {
            Long userId = jwtUtils.getUserIdFromToken(token);
            String openid = jwtUtils.getOpenidFromToken(token);
            
            if (userId != null) {
                UserContextHolder.setUserId(userId);
                UserContextHolder.setOpenid(openid);
                log.debug("设置用户上下文: userId={}, openid={}", userId, openid);
            } else {
                log.warn("无法从令牌中获取用户ID: {}", requestPath);
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return false;
            }
        } catch (Exception e) {
            log.error("处理认证令牌时发生错误: {}", e.getMessage());
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }

        return true;
    }

    /**
     * 请求处理完成后的清理
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 清除用户上下文，防止内存泄漏
        UserContextHolder.clear();
    }

    /**
     * 从请求中获取JWT令牌
     * 
     * @param request HTTP请求
     * @return JWT令牌
     */
    private String getTokenFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader(jwtProperties.getHeaderName());
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(jwtProperties.getTokenPrefix())) {
            return bearerToken.substring(jwtProperties.getTokenPrefix().length());
        }
        return null;
    }

    /**
     * 判断是否为公开路径（不需要认证）
     * 
     * @param path 请求路径
     * @return 是否为公开路径
     */
    private boolean isPublicPath(String path) {
        // 公开接口列表（注意：路径已包含context-path /bookOcean）
        String[] publicPaths = {
            "/bookOcean/user/login",                    // 登录接口
            "/bookOcean/user/updateUserAvatar",         // 更新用户头像（首次登录时需要）
            "/bookOcean/daily-quote/getDailyQuote",     // 每日一句接口（公开）
            "/bookOcean/file/upload/cover",             // 封面上传接口
            "/bookOcean/file/upload/image",             // 图片上传接口
            "/bookOcean/user-profile/agreement/check",  // 协议检查接口（登录前也需要检查）
            "/health",                                  // 健康检查
            "/actuator/**",                             // Spring Boot Actuator
            "/swagger-ui/**",                           // Swagger UI
            "/v3/api-docs/**",                         // OpenAPI 文档
            "/favicon.ico",                             // 图标
            "/static/**",                               // 静态资源
            "/upload/**"                                // 文件上传
        };

        for (String publicPath : publicPaths) {
            if (publicPath.endsWith("/**")) {
                // 通配符匹配
                String prefix = publicPath.substring(0, publicPath.length() - 3);
                if (path.startsWith(prefix)) {
                    log.debug("路径 {} 匹配公开通配符规则: {}", path, publicPath);
                    return true;
                }
            } else if (path.equals(publicPath)) {
                // 精确匹配
                log.debug("路径 {} 匹配公开精确规则: {}", path, publicPath);
                return true;
            }
        }

        log.debug("路径 {} 不匹配任何公开规则，需要认证", path);
        return false;
    }
}
